#include <chrono>
#include <immintrin.h>
#include <iostream>
#include <stdio.h>
#include <vector>

using namespace std;

int* AVX4K(const int a[1024], const int b[1024], int c[1024])
{
    int m = 0xFFFFFFFF;
    __m256i loada;
    __m256i loadb;
    __m256i loadc;
    for (int i = 0; i < 32; i++) {
        loada = _mm256_lddqu_si256((__m256i*)(a + 32 * i));
        loadb = _mm256_loadu_si256((__m256i*)(b + 32 * i));
        loadc = _mm256_xor_si256(loada, loadb);
        _mm256_storeu_si256((__m256i*)(c + 32 * i), loadc);

        loada = _mm256_loadu_si256((__m256i*)(a + 32 * i + 8));
        loadb = _mm256_loadu_si256((__m256i*)(b + 32 * i + 8));
        loadc = _mm256_xor_si256(loada, loadb);
        _mm256_storeu_si256((__m256i*)(c + 32 * i + 8), loadc);

        loada = _mm256_loadu_si256((__m256i*)(a + 32 * i + 16));
        loadb = _mm256_loadu_si256((__m256i*)(b + 32 * i + 16));
        loadc = _mm256_xor_si256(loada, loadb);
        _mm256_storeu_si256((__m256i*)(c + 32 * i + 16), loadc);

        loada = _mm256_loadu_si256((__m256i*)(a + 32 * i + 24));
        loadb = _mm256_loadu_si256((__m256i*)(b + 32 * i + 24));
        loadc = _mm256_xor_si256(loada, loadb);
        _mm256_storeu_si256((__m256i*)(c + 32 * i + 24), loadc);
    }
    return 0;
}

int* AVX4M(const int a[1024 * 1024], const int b[1024 * 1024], int c[1024 * 1024])
{
    for (int i = 0; i < 1024; i++) {
        AVX4K(a + i * 1024, b + i * 1024, c + i * 1024);
    }
    return 0;
}

const uint64_t dataLen = (uint64_t)1024 * 512;
const uint64_t blockSize = 1024 * 4;

int main()
{
    auto pos1 = chrono::steady_clock::now();
    vector<int> data1(dataLen / sizeof(int), 1), data3(dataLen / sizeof(int));
    vector<int> data2(dataLen / sizeof(int), 2);
    auto pos2 = chrono::steady_clock::now();
    chrono::duration<double, milli> dur1 = pos2 - pos1;
    cout << dur1.count() << endl;
    auto pos4 = chrono::steady_clock::now();

    for (uint64_t i = 0, data_begin = 0; i < dataLen / blockSize; i++, data_begin += blockSize / sizeof(int)) {
        // AVX4M(&data1[data_begin], &data2[0], &data3[data_begin]);
        AVX4K(&data1[data_begin], &data2[data_begin], &data3[data_begin]);
    }
    auto pos3 = chrono::steady_clock::now();
    chrono::duration<double, milli> dur2 = pos3 - pos4;
    cout << dur2.count() << endl;

    for (uint64_t i = 0; i < 16; i++) {
        cout << data3[(dataLen - blockSize) / sizeof(int) + i];
    }
    cout << endl;
}